package com.zeus.mongo;

import com.zeus.mongo.mapper.ZeusExampleMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.CommandLineRunner;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.convert.DefaultMongoTypeMapper;
import org.springframework.data.mongodb.core.convert.MappingMongoConverter;
import org.springframework.data.mongodb.core.convert.MongoExampleMapper;
import org.springframework.data.mongodb.core.convert.QueryMapper;
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
import org.springframework.util.ReflectionUtils;

import java.lang.reflect.Field;
import java.util.Objects;

/**
 * @author magic
 * @date 19-7-18 上午10:49
 * @version 1.0.0
 * Description ZeusMongoAutoConfiguration
 * 
 */
@Configuration
public class ZeusMongoAutoConfiguration implements CommandLineRunner {

    private MongoTemplate mongoTemplate;
    private MappingMongoConverter mappingMongoConverter;
    private MongoMappingContext mongoMappingContext;

    @Value("${zeus.mongo.resolve.class:true}")
    private Boolean resolveClass;

    final static Logger LOGGER = LoggerFactory.getLogger(ZeusMongoAutoConfiguration.class);

    public ZeusMongoAutoConfiguration(ObjectProvider<MongoTemplate> mongoTemplateObjectProvider,
                                      ObjectProvider<MappingMongoConverter> mappingMongoConverterObjectProvider,
                                      ObjectProvider<MongoMappingContext> mongoMappingContextObjectProvider){
        this.mongoTemplate = mongoTemplateObjectProvider.getIfAvailable();
        this.mappingMongoConverter = mappingMongoConverterObjectProvider.getIfAvailable();
        this.mongoMappingContext = mongoMappingContextObjectProvider.getIfAvailable();
    }

    @Override
    public void run(String... args) throws Exception {

        if(Objects.nonNull(mongoTemplate) && Objects.nonNull(mappingMongoConverter)){
            Field queryMapper = ReflectionUtils.findField(MongoTemplate.class, "queryMapper", QueryMapper.class);
            Field exampleMapper = ReflectionUtils.findField(QueryMapper.class, "exampleMapper", MongoExampleMapper.class);
            ReflectionUtils.makeAccessible(queryMapper);
            ReflectionUtils.makeAccessible(exampleMapper);
            Object target = null;
            try {
                target = queryMapper.get(mongoTemplate);
                exampleMapper.set(target,new ZeusExampleMapper(mappingMongoConverter));
            } catch (IllegalAccessException e) {
                LOGGER.warn("ZeusMongoAutoConfiguration patch mongoTemplate fail, err = ",e);
            }
        }

        if(resolveClass &&Objects.nonNull(mappingMongoConverter) && Objects.nonNull(mongoMappingContext)){
            DefaultMongoTypeMapper typeMapper = new DefaultMongoTypeMapper(null, mongoMappingContext);
            mappingMongoConverter.setTypeMapper(typeMapper);
            LOGGER.info("ZeusMongoAutoConfiguration patch mappingMongoConverter success ");
        }
    }
}

